package org.snlab.compiler;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Set;

import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;

public class DFA {
    private Graph<DFANode, TransferEdge> graph = new DefaultDirectedGraph<>(TransferEdge.class);
    private DFANode start;
    private DFANode accept;

    public static DFA fromFile(String fn) {
        DFA dfa = new DFA();
        File f = new File(fn);
        Scanner in = null;
        try {
            in = new Scanner(f);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        while (in.hasNextLine()) {
            String line = in.nextLine();
            String[] tokens = line.split(" ");
            DFANode src = dfa.getOrCreateNode(Compiler.topology.getDeviceByName(tokens[0]));
            DFANode dst = dfa.getOrCreateNode(Compiler.topology.getDeviceByName(tokens[1]));
            if (!dfa.getGraph().containsVertex(src)) {
                dfa.getGraph().addVertex(src);
            }
            if (!dfa.getGraph().containsVertex(dst)) {
                dfa.getGraph().addVertex(dst);
            }
            TransferEdge edge = new TransferEdge(tokens[1]);
            dfa.getGraph().addEdge(src, dst, edge);
        }
        return dfa;
    }

    public DFANode getOrCreateNode(Device device) {
        for (DFANode node : this.graph.vertexSet()) {
            if (node.getDevice() == device) {
                return node;
            }
        }
        DFANode node = new DFANode(device, this);
        this.graph.addVertex(node);
        return node;
    }

    public void newState(DFANode state) {
        this.graph.addVertex(state);
    }

    public void newStates(Set<DFANode> states) {
        for (DFANode s : states) {
            this.newState(s);
        }
    }

    public void newTransfer(DFANode from, DFANode to, String symbol) {
        this.graph.addEdge(from, to, new TransferEdge(symbol));
    }

    public void setStart(DFANode state) {
        this.start = state;
    }

    public void setAccept(DFANode state) {
        this.accept = state;
    }

    /**
     * @return Graph<DFANode, DefaultEdge> return the graph
     */
    public Graph<DFANode, TransferEdge> getGraph() {
        return graph;
    }

    /**
     * @param graph the graph to set
     */
    public void setGraph(Graph<DFANode, TransferEdge> graph) {
        this.graph = graph;
    }

    /**
     * @return DFANode return the start
     */
    public DFANode getStart() {
        return start;
    }

    /**
     * @return DFANode return the accept
     */
    public DFANode getAccept() {
        return accept;
    }

}

class TransferEdge extends DefaultEdge {
    private String symbol;

    public TransferEdge(String symbol) {
        this.symbol = symbol;
    }

    public String getSymbol() {
        return this.symbol;
    }

    /**
     * @param symbol the symbol to set
     */
    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

}